home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / db / esm-3.1 / esm-3 / usr / local / sm / src / serverlib / recover / restart.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  10.2 KB  |  395 lines

  1. /*
  2.  *   $RCSfile: restart.C,v $  
  3.  *   $Revision: 1.1.1.1 $  
  4.  *   $Date: 1996/05/04 21:55:55 $      
  5.  */ 
  6. /**********************************************************************
  7. * EXODUS Database Toolkit Software
  8. * Copyright (c) 1991 Computer Sciences Department, University of
  9. *                    Wisconsin -- Madison
  10. * All Rights Reserved.
  11. *
  12. * Permission to use, copy, modify and distribute this software and its
  13. * documentation is hereby granted, provided that both the copyright
  14. * notice and this permission notice appear in all copies of the
  15. * software, derivative works or modified versions, and any portions
  16. * thereof, and that both notices appear in supporting documentation.
  17. *
  18. * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
  19. * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.  
  20. * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  21. * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  22. *
  23. * The EXODUS Project Group requests users of this software to return 
  24. * any improvements or extensions that they make to:
  25. *
  26. *   EXODUS Project Group 
  27. *     c/o David J. DeWitt and Michael J. Carey
  28. *   Computer Sciences Department
  29. *   University of Wisconsin -- Madison
  30. *   Madison, WI 53706
  31. *
  32. *     or exodus@cs.wisc.edu
  33. *
  34. * In addition, the EXODUS Project Group requests that users grant the 
  35. * Computer Sciences Department rights to redistribute these changes.
  36. **********************************************************************/
  37.  
  38. #include "sysdefs.h"
  39. #include "ess.h"
  40. #include "checking.h"
  41. #include "trace.h"
  42. #include "error.h"
  43. #include "list.h"
  44. #include "pool.h"
  45. #include "tid.h"
  46. #include "io.h"
  47. #include "lock.h"
  48. #include "object.h"
  49. #include "msgdefs.h"
  50. #include "thread.h"
  51. #include "semaphore.h"
  52. #include "latch.h"
  53. #include "link.h"
  54. #include "lsn.h"
  55. #include "bf.h"
  56. #include "volume.h"
  57. #include "openlog.h"
  58. #include "trans.h"
  59. #include "log.h"
  60. #include "logrecs.h"
  61. #include "threadstate.h"
  62. #include "adminmsg.h"
  63. #include "util_funcs.h"
  64. #include "log_intfuncs.h"
  65. #include "log_extfuncs.h"
  66. #include "recover_intfuncs.h"
  67. #include "trans_extfuncs.h"
  68. #include "bf_extfuncs.h"
  69. #include "io_extfuncs.h"
  70. #include "thread_funcs.h"
  71. #include "admin_funcs.h"
  72. #include "thread_globals.h"
  73. #include "log_globals.h"
  74. #include "processStats.h"
  75. #include "distr.h"
  76. #include "distr_extfuncs.h"
  77.  
  78. extern FILE     *sm_ErrorStream;
  79.  
  80.  
  81.  void
  82. restart (
  83.  
  84.     OPENLOG                    *openLog 
  85. )
  86. {
  87.  
  88.     register LOGRECORDHDR    *record;
  89.     register FOUR            offset;
  90.     register LOGPAGEHDR        *pageHeader;
  91.     register LOGPAGEHDR        *endHeader;
  92.     register GROUPLINK        *groupLink;
  93.     CHECKPOINTMASTER        *checkMaster;
  94.     LSNOFFSET                checkpointLSN;
  95.     LSNOFFSET                oldestLSN;
  96.     LSNOFFSET                lastLSN;
  97.     DIRTYPAGEINFO            *oldestPage;
  98.     TRANSREC                *oldestTrans;
  99.     PID                        pid;
  100.     ProcessStats            phaseTime;
  101.     ProcessStats            recoveryTime;
  102.     GROUPLINK                *logRecordBuffer = NULL;
  103. #ifdef DEBUG
  104.     LSN                        debugLSN;
  105. #endif DEBUG
  106.  
  107.     TRACE(TR_LOG|TR_RECOVER, TR_LEVEL_1);
  108.  
  109.     CheckpointsEnabled = FALSE;  // do not allow checkpoints
  110.  
  111.     recoveryTime.Start();
  112.  
  113.     /*
  114.      *    fill in the volume id
  115.      */
  116.     pid.volid = openLog->volid;    
  117.  
  118.     /*
  119.      *    get a pointer to the checkpoint info
  120.      */
  121.     checkMaster = (CHECKPOINTMASTER *) openLog->controlBuffer->bufFrame;
  122.  
  123.     /*
  124.      *    get the lsn of the most recent checkpoint record
  125.      */
  126.     checkpointLSN = checkMaster->checkRecordLSN.offset;
  127.     LastFlushedCheckpoint = checkMaster->checkRecordLSN;
  128.     OldestDirtyPageLSN = LastFlushedCheckpoint;
  129.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_2, ("checkpointLSN:%d", checkpointLSN));
  130.  
  131.     /*
  132.      *    calculate the page the checkpoint record LSN is on
  133.      */
  134.     pid.page = LSN_TO_BLOCK(checkpointLSN, openLog);
  135.     TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("log page:%d", pid.page - openLog->logFileAddr));
  136.  
  137.     /*
  138.      *    read in the checkpoint record log page
  139.      */
  140.     if ((groupLink = bf_ReadPage(openLog->readGroup, &pid,
  141.                                  openLog->page2size, NOFLAGS)) == NULL)    {
  142.         fprintf(sm_ErrorStream, "SERVER ERROR: log volume may need to be regenerated if this is the\n");
  143.         fprintf(sm_ErrorStream, "              first time it has been used since being formatted.\n");
  144.         admin_ShutServer(SHUT_ABNORMAL_EXIT);
  145.     }
  146.  
  147.     /*
  148.      *    get a pointer to the page header and tailers
  149.      */
  150.     pageHeader = (LOGPAGEHDR *) groupLink->bufFrame;
  151.     endHeader  = (LOGPAGEHDR *) (((char *) pageHeader) + openLog->lastUsableByte);
  152.  
  153.     /*
  154.      *    check the page numbers
  155.      */
  156.     SM_ASSERT(LEVEL_1, pageHeader->pageNumber == LSN_TO_LOG_PAGE(checkpointLSN, openLog));
  157.     SM_ASSERT(LEVEL_1, endHeader->pageNumber == LSN_TO_LOG_PAGE(checkpointLSN, openLog));
  158.  
  159.     /*
  160.      *    check to make sure the magic is ok
  161.      *    this is fatal since all sectors have a valid magic
  162.      */
  163.     if (CHECK_LOGPAGE_MAGIC(pageHeader) || CHECK_LOGPAGE_MAGIC(endHeader))    {
  164.  
  165.         SM_ERROR(TYPE_FATAL, esmBADLOGPAGEHEADER);
  166.     }
  167.  
  168.     /*
  169.      *    calculate the offset of the checkpoint record
  170.      */
  171.     offset = LOG_PAGE_OFFSET(checkpointLSN, openLog);
  172.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_2, ("oldest page offset:%d", offset));
  173.  
  174.     /*
  175.      *    check to make sure that the lastRecord field is consistent
  176.      */
  177.     if (endHeader->lastRecord < offset)    {
  178.  
  179.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  180.     }
  181.  
  182.     /*
  183.      *    get a pointer to the record header
  184.      */
  185.     record = (LOGRECORDHDR *) (groupLink->bufFrame + offset);
  186.  
  187.     /*
  188.      *    check to see if the record resides on a page
  189.      */
  190.     if ((openLog->lastUsableByte - offset) < record->length)    {
  191.  
  192.         logRecordBuffer = getLogRecordBuffer(record->length);
  193.         SM_ASSERT(LEVEL_3, logRecordBuffer != NULL);
  194.  
  195.         /*
  196.          *    combine the record
  197.          */
  198.         if (combineRecord(openLog, record, (openLog->lastUsableByte - offset), FALSE, logRecordBuffer) != esmNOERROR)    {
  199.             
  200.             /*
  201.              *    Reached end of log
  202.              */
  203.             SM_ERROR(TYPE_FATAL, esmINTERNAL);
  204.         }
  205.  
  206.         /*
  207.          *    get a pointer to the record header
  208.          */
  209.         record = (LOGRECORDHDR *) logRecordBuffer->bufFrame;
  210.     }
  211.  
  212.     /*
  213.      *    check to make sure the magic matches
  214.      */
  215.     if (CHECK_LOGRECORD_MAGIC(record))    {
  216.  
  217.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  218.     }
  219.  
  220.     /*
  221.      *    initialize the dirty page table
  222.      */
  223.     clearDirtyPageTable();
  224.  
  225.     /*
  226.      *    Unfix the checkpoint log record page
  227.      */
  228.     bf_UnfixPage(groupLink, BF_DEFAULT, FALSE);
  229.  
  230.     /*
  231.      *    do the analysis phase
  232.      */
  233.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("beginning ANALYSIS"));
  234.     phaseTime.Start();
  235.     lastLSN = processLogForward(openLog, checkpointLSN, ANALYSIS_PHASE);
  236.     phaseTime.Stop();
  237.     fprintf(sm_ErrorStream, "Recovery Statistics:\n");
  238.     phaseTime.PrintStatsHeader(sm_ErrorStream);
  239.     phaseTime.PrintStats(sm_ErrorStream, "AnlysPass");
  240.  
  241.     /*
  242.      *    Determine the oldest LSN in the dirty page table
  243.      *  and the oldest firstLSN for any transaction which is
  244.      *  prepared or committed but not ended
  245.      *    Use this to determine where to begin redo
  246.      */
  247.     oldestPage = findOldestDirtyPage();
  248.     oldestTrans = findOldestTrans();
  249.  
  250.     if ((oldestPage == NULL) && (oldestTrans == NULL)) {
  251.         TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("both NULL"));
  252.         oldestLSN = checkpointLSN;
  253.     }
  254.     else if (oldestPage == NULL) {
  255.         TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("oldestPage NULL"));
  256.         oldestLSN = oldestTrans->prepareLSN.offset;
  257.     }
  258.     else if (oldestTrans == NULL) {
  259.         TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("oldestTrans NULL"));
  260.         oldestLSN = oldestPage->lsn.offset;
  261.     }
  262.     else {
  263.         TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("neither NULL"));
  264.         if (compareLSN(&(oldestTrans->prepareLSN), &(oldestPage->lsn)) < 0)
  265.             oldestLSN = oldestTrans->prepareLSN.offset;
  266.         else
  267.             oldestLSN = oldestPage->lsn.offset;
  268.     }
  269.  
  270.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("oldestLSN:%d",oldestLSN));
  271.     /*
  272.      *    Remember the last record in the log so that volumes can
  273.      *    be mounted properly
  274.      */
  275.     openLog->nextValidLSN.offset = lastLSN;
  276.     openLog->nextValidLSN.wrapCount = openLog->wrapCount;
  277.  
  278.     /*
  279.      *    Mount all necessary volumes
  280.      */
  281.     if (mountRecoveryVolumes() != esmNOERROR) {
  282.         fprintf(sm_ErrorStream, 
  283.             "Cannot mount volumes needed for recovery!\n");
  284.         admin_ShutServer(SHUT_ABNORMAL_EXIT);
  285.     }
  286.  
  287.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("beginning REDO"));
  288.     phaseTime.Start();
  289.     lastLSN = processLogForward(openLog, oldestLSN, REDO_PHASE);
  290.     phaseTime.Stop();
  291.     phaseTime.PrintStats(sm_ErrorStream, "RedoPass");
  292.  
  293. #ifdef DEBUG
  294.  
  295.     /*
  296.      *    Since redo brings the system to a consistent state, 
  297.      *    make sure all the volumes' bitmaps are in order
  298.      */
  299.     if (io_CheckAllVolumes() != esmNOERROR) {
  300.         
  301.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  302.     }
  303. #endif DEBUG
  304.  
  305.     /*
  306.      *    setup the tail page of the log
  307.      */
  308.     openLog->tailPid = (lastLSN >> openLog->page2size);
  309.     openLog->tailLSN = lastLSN;
  310.  
  311. #ifdef DEBUG
  312.     /* make sure we don't overwrite important log records */
  313.     debugLSN.offset = openLog->tailLSN;
  314.     debugLSN.wrapCount = openLog->wrapCount;
  315.     debugLSN.wrapCount--; 
  316.     if(compareLSN(&debugLSN, &OldestDirtyPageLSN) >= 0) {
  317.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  318.     }
  319. #endif DEBUG
  320.  
  321.     CheckpointsEnabled = TRUE;  // allow checkpoints
  322.  
  323.     /*
  324.      *  take care of the distr trans left outstanding
  325.      *    NOTE: this also sets up openLog so that the
  326.      *    active prtion of the log is not overwritten 
  327.      *    during undo
  328.      *    Hence, this must be called before calling recoverUndo
  329.      */
  330.     recoverPreparedTrans();
  331.  
  332.     /*
  333.      *    setup undo for the remaining transactions
  334.      */
  335.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("beginning UNDO"));
  336.     phaseTime.Start();
  337.  
  338.     /*
  339.      *    undo the remaining transactions
  340.      */
  341.     recoverUndo(lastLSN);
  342.     phaseTime.Stop();
  343.     phaseTime.PrintStats(sm_ErrorStream, "UndoPass");
  344.  
  345.     /*
  346.      *    Print recovery time statistics
  347.      */
  348.     recoveryTime.Stop();
  349.     recoveryTime.PrintStats(sm_ErrorStream, "RecovTime");
  350.  
  351.     if (logRecordBuffer != NULL) {
  352.         freeLogRecordBuffer(logRecordBuffer);
  353.         logRecordBuffer = NULL;
  354.     }
  355.  
  356. #ifdef DEBUG
  357.     /*
  358.      *    Since undo brings the system to a consistent state, 
  359.      *    make sure all the volumes' bitmaps are in order
  360.      */
  361.     if (io_CheckAllVolumes() != esmNOERROR) {
  362.         
  363.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  364.     }
  365.  
  366.     /* make sure we don't overwrite important log records */
  367.     debugLSN.offset = openLog->tailLSN;
  368.     debugLSN.wrapCount = openLog->wrapCount;
  369.     debugLSN.wrapCount--; 
  370.     if(compareLSN(&debugLSN, &OldestDirtyPageLSN) >= 0) {
  371.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  372.     }
  373. #endif DEBUG
  374.  
  375.     /* 
  376.      *  force a checkpoint which flushes all pages and
  377.      *    wait for the checkpoint to complete 
  378.      */
  379.     activateCheckpoint(TRUE, TRUE, TRUE);
  380.  
  381.     /*
  382.      *    Unmount all volumes used in recovery
  383.      */
  384.     if (dismountRecoveryVolumes() != esmNOERROR) {
  385.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  386.     }
  387.     {
  388.         int i;
  389.         if( (i=io_NumOpenVolumes()) > 1) {
  390.             fprintf(sm_ErrorStream, "PREPARED transactions were recovered; ");
  391.             fprintf(sm_ErrorStream, "%d volumes are mounted.\n", i);
  392.         }
  393.     }
  394. }
  395.